class_name GameplayEffect
## 游戏效果系统（支持持续效果、周期触发、效果堆叠）
## Version: 0.2.0

##
var effect_asset: GameplayEffectAsset

##
var active: bool = true

##
var source: AbilitySystemComponent

##
var target: AbilitySystemComponent

## 效果已持续时间
var elapsed_time: float = 0.0

## 效果距离下个触发周期的时间
var next_period_time: float = 0.0

##
var is_expired: bool = false

##
var stack_count: int = 0


func _init(
	init_effect_asset: GameplayEffectAsset,
	init_source: AbilitySystemComponent,
	init_target: AbilitySystemComponent,
) -> void:
	effect_asset = init_effect_asset
	source = init_source
	target = init_target
	
	if effect_asset.period > 0:
		next_period_time = effect_asset.period


func on_attach() -> void:
	if effect_asset.duration_policy != GameplayEffectAsset.DurationPolicy.Instant:
		target.tag_manager.add_tags(effect_asset.granted_tags)
		target.ability_manager.grant_abilities(effect_asset.granted_abilities)


func on_update(delta: float) -> void:
	if is_expired or not active:
		return
	
	elapsed_time += delta
	
	if effect_asset.period > 0:
		while elapsed_time >= next_period_time:
			execute_effect()
			next_period_time += effect_asset.period
	
	if effect_asset.duration_policy == GameplayEffectAsset.DurationPolicy.Duration and\
	   elapsed_time >= effect_asset.duration:
		is_expired = true


func on_detach() -> void:
	if effect_asset.duration_policy != GameplayEffectAsset.DurationPolicy.Instant:
		target.ability_manager.remove_abilities(effect_asset.granted_abilities)
		target.tag_manager.remove_tags(effect_asset.granted_tags)


func execute_effect() -> void:
	if not active:
		return

	var attribute := target.attribute_set.get_attribute(effect_asset.attribute_name)

	# 判断是否需要同时修改 base 和 current
	var modify_both := (
		effect_asset.duration_policy == GameplayEffectAsset.DurationPolicy.Instant 
		or effect_asset.period > 0
	)

	for modifier in effect_asset.modifiers:
		var magnitude = modifier.get_magnitude(source, target)
		
		# 处理需要同时修改 base 和 current 的情况
		if modify_both:
			match modifier.operation:
				GameplayEffectModifier.Operation.Override:
					attribute.base_value = magnitude
					attribute.current_value = magnitude
				GameplayEffectModifier.Operation.Add:
					attribute.base_value += magnitude
					attribute.current_value += magnitude
				GameplayEffectModifier.Operation.Minus:
					attribute.base_value -= magnitude
					attribute.current_value -= magnitude
				GameplayEffectModifier.Operation.Multiply:
					attribute.base_value *= magnitude
					attribute.current_value *= magnitude
				GameplayEffectModifier.Operation.Divide:
					assert(magnitude != 0, "Division by zero in modifier operation")
					attribute.base_value /= magnitude
					attribute.current_value /= magnitude
		
		# 处理仅修改 current 的情况
		else:
			match modifier.operation:
				GameplayEffectModifier.Operation.Override:
					attribute.current_value = magnitude
				GameplayEffectModifier.Operation.Add:
					attribute.current_value += magnitude
				GameplayEffectModifier.Operation.Minus:
					attribute.current_value -= magnitude
				GameplayEffectModifier.Operation.Multiply:
					attribute.current_value *= magnitude
				GameplayEffectModifier.Operation.Divide:
					assert(magnitude != 0, "Division by zero in modifier operation")
					attribute.current_value /= magnitude


func reset_duration() -> void:
	next_period_time = next_period_time + effect_asset.period
